package cn.jbolt.ai.resource.llm.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.jbolt.util.JSONUtil;
import cn.jbolt.util.Pager;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.jbolt.ai.resource.llm.dao.AiResourceMapper;
import cn.jbolt.ai.resource.llm.entity.AiResource;
import cn.jbolt.ai.resource.llm.service.AiResourceService;
import cn.jbolt.ai.resource.llm.vo.ResourceSelectVO;
import cn.jbolt.util.Result;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.jboltai.resource.ResourceCenter;
import com.jboltai.resource.ai.AIModel;
import com.jboltai.resource.ai.AIResource;
import com.jboltai.resource.ai.AIResourceCenter;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class AiResourceServiceImpl extends ServiceImpl<AiResourceMapper, AiResource> implements AiResourceService {

    private static final Logger logger = LoggerFactory.getLogger(AiResourceServiceImpl.class);

    @Override
    public Result<AiResource> getResourceById(Long id) {
        AiResource resource = this.getById(id);
        if (resource != null) {
            return Result.success(resource);
        } else {
            return Result.error("资源不存在");
        }

    }

    @Override
    public Result<Pager> listByPage(Integer pageNumber, Integer pageSize, String keywords) {
        QueryWrapper<AiResource> queryWrapper = new QueryWrapper();
        if (StrUtil.isNotBlank(keywords)) {
            queryWrapper.and(wrapper -> wrapper.like("name", keywords).
                    or().
                    like("type", keywords));
        }
        queryWrapper.orderByDesc("id");
        return Result.success(Pager.from(this.page(new Page<>(pageNumber, pageSize), queryWrapper)));
    }

    @Override
    public Result listAllEnabledType() {
        List<ResourceSelectVO> selectList = convertToTypeOptions(this.list(new QueryWrapper<AiResource>()
                        .select("type", "default_model")
                .eq("enable", true).groupBy("type","default_model")));
        return Result.success(selectList);
    }

    private List<ResourceSelectVO> convertToTypeOptions(List<AiResource> list) {
        List<ResourceSelectVO> selectList = new ArrayList<>();
        for (AiResource resource : list) {
            ResourceSelectVO selectVO = new ResourceSelectVO();
            selectVO.setSn(resource.getType()+":"+(StrUtil.isNotBlank(resource.getDefaultModel())?resource.getDefaultModel():""));
            selectVO.setName(AIModel.get(resource.getType()).getName()+" : "+
                    (StrUtil.isNotBlank(resource.getDefaultModel())?resource.getDefaultModel():"默认"));
            selectList.add(selectVO);
        }
        return selectList;
    }

    @Override
    @Transactional
    public Result add(AiResource resource) {
        resource.setEnable(true);
        boolean save = this.save(resource);
        if (save) {
            //注册资源
            Result result = registerResource(resource);
            if (result.isError()) {
//                throw new RuntimeException("资源注册失败");
                return Result.error("资源注册失败");
            }
            return Result.success();
        } else {
            return Result.error("添加失败");
        }

    }

    @Override
    @Transactional
    public Result update(AiResource resource) {
        if (updateById(resource)) {
            if (resource.getEnable()) {
                unRegisterResource(resource);
                Result result = registerResource(resource);
                if (result.isError()) {
//                    throw new RuntimeException("资源注册失败");
                    return Result.error("资源注册失败");
                }
            }
            return Result.success();
        } else {
            return Result.error("更新失败");
        }
    }

    @Override
    @Transactional
    public Result del(Long id) {
        Result<AiResource> Result = getResourceById(id);
        if (Result.isError()) {
            return Result;
        }
        AiResource resource = Result.getData();
        if (resource.getEnable()) {
            unRegisterResource(resource);
        }
        if (removeById(id)) {
            return Result.success();
        } else {
            return Result.error("删除失败");
        }
    }

    @Override
    @Transactional
    public Result toggleEnable(Long id) {
        AiResource resource = this.getById(id);
        Boolean enable = !resource.getEnable();
        if (this.update(new UpdateWrapper<AiResource>().eq("id", id).set("enable", enable))) {
            if (enable == false) { //关闭状态的时候,移除资源
                unRegisterResource(resource);
                return Result.success();
            } else {//打开状态,注册资源
                Result result = registerResource(resource);
                if (result.isError()) {
//                    throw new RuntimeException("资源注册失败");
                    return Result.error("资源注册失败");

                }
                return Result.success();
            }
        } else {
            return Result.error("更新启用状态失败");
        }
    }

    /**
     * 注册资源
     *
     * @param resource
     */
    public Result registerResource(@NotNull AiResource resource) {
        logger.info("AI资源--{}--注册资源", resource.getType());
        try {
            AIResource jboltAIResource = new AIResource(AIModel.get(resource.getType()),
                    resource.getId().toString(),
                    StrUtil.isBlankIfStr(resource.getApiKey()) == true ? null : resource.getApiKey());
            //判断默认模型型号
            if (StrUtil.isNotBlank(resource.getDefaultModel())) {
                jboltAIResource.setDefaultModelName(resource.getDefaultModel());
            }
            //判断大模型需要的SECRET KEY
            if (StrUtil.isNotBlank(resource.getApiSecret())) {
                jboltAIResource.setAppSecret(resource.getApiSecret());
            }
            //判断接口地址
            if (StrUtil.isNotBlank(resource.getApiUrl())) {
                jboltAIResource.setApiUrl(resource.getApiUrl());
            }

            //判断请求频率
            if (StrUtil.isNotBlank(resource.getLimits())) {
                if (JSONUtil.isTypeJSONArray(resource.getLimits())) {
                    ArrayNode jsonArray = JSONUtil.toJsonArray(resource.getLimits());
                    for (int i = 0; i < jsonArray.size(); i++) {
                        JsonNode jsonObject = jsonArray.get(i);
                        String unit = jsonObject.get("unit").asText();
                        int times = jsonObject.get("times").asInt();
                        if (times <= 0) continue;

                        TimeUnit timeUnit = null;
                        switch (unit.toLowerCase()) {
                            case "minute":
                                timeUnit = TimeUnit.MINUTES;
                                break;
                            case "hour":
                                timeUnit = TimeUnit.HOURS;
                                break;
                            case "day":
                                timeUnit = TimeUnit.DAYS;
                                break;
                        }
                        jboltAIResource.setRequestLimit(timeUnit, times);
                    }
                }

            }
            AIResourceCenter.register(jboltAIResource);

        } catch (Exception e) {
            String message = e.getMessage();
            logger.error("AI资源--{}--注册资源失败,异常原因:{}", resource.getType(), message);
            return Result.error(message);
        }
        return Result.success();

    }

    /**
     * 移除资源
     *
     * @param resource 资源
     */
    public void unRegisterResource(AiResource resource) {

        logger.info("AI资源--{}--移除资源", resource.getType());
        try {
            ResourceCenter.unregisterAI(resource.getId().toString());
        } catch (Exception e) {
            logger.error("AI资源--{}--移除资源失败,异常原因:{}", resource.getType(), e.getMessage());
            throw e;

        }
    }

    /**
     * 注册所有资源,是在项目启动时候调用
     */
    public void registerAllResource() {
        //只启动开启状态的资源
        this.list(new QueryWrapper<AiResource>().eq("enable", true)).
                forEach(this::registerResource);
    }
}
